{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "c44c5494-950d-4d2f-8d4f-b87b57c5b330",
   "metadata": {},
   "outputs": [],
   "source": [
    "# imports\n",
    "\n",
    "import os\n",
    "import requests\n",
    "from bs4 import BeautifulSoup\n",
    "from typing import List\n",
    "from dotenv import load_dotenv\n",
    "from openai import OpenAI\n",
    "import google.generativeai\n",
    "import anthropic"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "d1715421-cead-400b-99af-986388a97aff",
   "metadata": {},
   "outputs": [],
   "source": [
    "import gradio as gr # oh yeah!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "337d5dfc-0181-4e3b-8ab9-e78e0c3f657b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "OpenAI API Key exists and begins sk-proj-\n",
      "Anthropic API Key exists and begins sk-ant-\n"
     ]
    }
   ],
   "source": [
    "# Load environment variables in a file called .env\n",
    "# Print the key prefixes to help with any debugging\n",
    "\n",
    "load_dotenv(override=True)\n",
    "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
    "anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n",
    "google_api_key = os.getenv('GOOGLE_API_KEY')\n",
    "\n",
    "if openai_api_key:\n",
    "    print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
    "else:\n",
    "    print(\"OpenAI API Key not set\")\n",
    "    \n",
    "if anthropic_api_key:\n",
    "    print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n",
    "else:\n",
    "    print(\"Anthropic API Key not set\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "22586021-1795-4929-8079-63f5bb4edd4c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Connect to OpenAI, Anthropic and Google; comment out the Claude or Google lines if you're not using them\n",
    "\n",
    "openai = OpenAI()\n",
    "claude = anthropic.Anthropic()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "b16e6021-6dc4-4397-985a-6679d6c8ffd5",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A generic system message - no more snarky adversarial AIs!\n",
    "system_message = \"You are a helpful assistant\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "02ef9b69-ef31-427d-86d0-b8c799e1c1b1",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "def stream_gpt(prompt, model_version):\n",
    "    messages = [\n",
    "        {\"role\": \"system\", \"content\": system_message},\n",
    "        {\"role\": \"user\", \"content\": prompt}\n",
    "      ]\n",
    "    stream = openai.chat.completions.create(\n",
    "        model=model_version,\n",
    "        messages=messages,\n",
    "        stream=True\n",
    "    )\n",
    "    result = \"\"\n",
    "    for chunk in stream:\n",
    "        result += chunk.choices[0].delta.content or \"\"\n",
    "        yield result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "41e98d2d-e7d3-4753-8908-185b208b4044",
   "metadata": {},
   "outputs": [],
   "source": [
    "def stream_claude(prompt, model_version):\n",
    "    result = claude.messages.stream(\n",
    "        model=model_version,\n",
    "        max_tokens=1000,\n",
    "        temperature=0.7,\n",
    "        system=system_message,\n",
    "        messages=[\n",
    "            {\"role\": \"user\", \"content\": prompt},\n",
    "        ],\n",
    "    )\n",
    "    response = \"\"\n",
    "    with result as stream:\n",
    "        for text in stream.text_stream:\n",
    "            response += text or \"\"\n",
    "            yield response"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "5786802b-5ed8-4098-9d80-9bdcf4f7685b",
   "metadata": {},
   "outputs": [],
   "source": [
    "# function using both dropdown values\n",
    "def stream_model(message, model_family, model_version):\n",
    "    if model_family == 'GPT':\n",
    "        result =  stream_gpt(message, model_version)\n",
    "    elif model_family == 'Claude':\n",
    "        result = stream_claude ( message, model_version)\n",
    "    yield from result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "0d30be74-149c-41f8-9eef-1628eb31d74d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "* Running on local URL:  http://127.0.0.1:7891\n",
      "* To create a public link, set `share=True` in `launch()`.\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div><iframe src=\"http://127.0.0.1:7891/\" width=\"100%\" height=\"500\" allow=\"autoplay; camera; microphone; clipboard-read; clipboard-write;\" frameborder=\"0\" allowfullscreen></iframe></div>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": []
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/var/folders/sh/yytd3s6n3wd6952jnw97_v940000gn/T/ipykernel_7803/4165844704.py:7: DeprecationWarning: The model 'claude-3-opus-20240229' is deprecated and will reach end-of-life on January 5th, 2026.\n",
      "Please migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.\n",
      "  yield from result\n",
      "Traceback (most recent call last):\n",
      "  File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/gradio/queueing.py\", line 626, in process_events\n",
      "    response = await route_utils.call_process_api(\n",
      "               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
      "  File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/gradio/route_utils.py\", line 322, in call_process_api\n",
      "    output = await app.get_blocks().process_api(\n",
      "             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
      "  File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/gradio/blocks.py\", line 2220, in process_api\n",
      "    result = await self.call_function(\n",
      "             ^^^^^^^^^^^^^^^^^^^^^^^^^\n",
      "  File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/gradio/blocks.py\", line 1743, in call_function\n",
      "    prediction = await utils.async_iteration(iterator)\n",
      "                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
      "  File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/gradio/utils.py\", line 785, in async_iteration\n",
      "    return await anext(iterator)\n",
      "           ^^^^^^^^^^^^^^^^^^^^^\n",
      "  File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/gradio/utils.py\", line 776, in __anext__\n",
      "    return await anyio.to_thread.run_sync(\n",
      "           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
      "  File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/anyio/to_thread.py\", line 56, in run_sync\n",
      "    return await get_async_backend().run_sync_in_worker_thread(\n",
      "           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
      "  File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/anyio/_backends/_asyncio.py\", line 2470, in run_sync_in_worker_thread\n",
      "    return await future\n",
      "           ^^^^^^^^^^^^\n",
      "  File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/anyio/_backends/_asyncio.py\", line 967, in run\n",
      "    result = context.run(func, *args)\n",
      "             ^^^^^^^^^^^^^^^^^^^^^^^^\n",
      "  File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/gradio/utils.py\", line 759, in run_sync_iterator_async\n",
      "    return next(iterator)\n",
      "           ^^^^^^^^^^^^^^\n",
      "  File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/gradio/utils.py\", line 923, in gen_wrapper\n",
      "    response = next(iterator)\n",
      "               ^^^^^^^^^^^^^^\n",
      "  File \"/var/folders/sh/yytd3s6n3wd6952jnw97_v940000gn/T/ipykernel_7803/4165844704.py\", line 7, in stream_model\n",
      "    yield from result\n",
      "  File \"/var/folders/sh/yytd3s6n3wd6952jnw97_v940000gn/T/ipykernel_7803/2139010203.py\", line 12, in stream_claude\n",
      "    with result as stream:\n",
      "  File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/anthropic/lib/streaming/_messages.py\", line 154, in __enter__\n",
      "    raw_stream = self.__api_request()\n",
      "                 ^^^^^^^^^^^^^^^^^^^^\n",
      "  File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/anthropic/_base_client.py\", line 1314, in post\n",
      "    return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls))\n",
      "                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
      "  File \"/opt/anaconda3/envs/llms/lib/python3.11/site-packages/anthropic/_base_client.py\", line 1102, in request\n",
      "    raise self._make_status_error_from_response(err.response) from None\n",
      "anthropic.NotFoundError: Error code: 404 - {'type': 'error', 'error': {'type': 'not_found_error', 'message': 'model: claude-3-opus-20240229'}}\n"
     ]
    }
   ],
   "source": [
    "\n",
    "# Define available model versions\n",
    "model_versions = {\n",
    "    \"GPT\": [\"gpt-4o-mini\", \"gpt-4.1-mini\", \"gpt-4.1-nano\", \"gpt-4.1\", \"o3-mini\"],\n",
    "    \"Claude\": [\"claude-3-haiku-20240307\", \"claude-3-opus-20240229\", \"claude-3-sonnet-20240229\"]\n",
    "}\n",
    "\n",
    "# Update second dropdown options based on first dropdown selection\n",
    "def update_model_versions(selected_model_family):\n",
    "    return gr.update(choices=model_versions[selected_model_family], value=model_versions[selected_model_family][0])\n",
    "\n",
    "\n",
    "with gr.Blocks() as demo:\n",
    "    model_family_dropdown = gr.Dropdown(\n",
    "            label=\"Select Model Family\",\n",
    "            choices=[\"GPT\", \"Claude\"],\n",
    "            value=\"GPT\"\n",
    "        )\n",
    "    model_version_dropdown = gr.Dropdown(\n",
    "            label=\"Select Model Version\",\n",
    "            choices=model_versions[\"GPT\"],  # Default choices\n",
    "            value=model_versions[\"GPT\"][0]\n",
    "        )\n",
    "    \n",
    "    message_input = gr.Textbox(label=\"Your Message\")\n",
    "    output = gr.Markdown(label=\"Response\")\n",
    "\n",
    "    # Bind logic to update model version dropdown\n",
    "    model_family_dropdown.change(\n",
    "        fn=update_model_versions,\n",
    "        inputs=model_family_dropdown,\n",
    "        outputs=model_version_dropdown\n",
    "    )\n",
    "\n",
    "    # Launch function on submit\n",
    "    submit_btn = gr.Button(\"Submit\")\n",
    "    submit_btn.click(\n",
    "        fn=stream_model,\n",
    "        inputs=[message_input, model_family_dropdown, model_version_dropdown],\n",
    "        outputs=output\n",
    "    )\n",
    "\n",
    "demo.launch()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bcd43d91-0e80-4387-86fa-ccd1a89feb7d",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
